package com.sprite.support.wechat.utils;

import java.util.Base64;

import com.sprite.support.wechat.utils.model.MpTemplateMessage;
import com.sprite.utils.http.FormData;
import com.sprite.utils.http.RawData;
import com.sprite.utils.http.RequestPayload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.sprite.support.wechat.utils.model.AccessToken;
import com.sprite.support.wechat.utils.model.CodeSession;
import com.sprite.support.wechat.utils.model.MpUserInfo;
import com.sprite.utils.UtilString;
import com.sprite.utils.cache.UtilCache;
import com.sprite.utils.crypto.UtilAES;
import com.sprite.utils.http.UtilHttp;

/**
 * 微信小程序相关接口
 * @author Jack
 */
public final class MpUtils {
	private static Logger logger = LoggerFactory.getLogger(MpUtils.class);

	private static boolean enableCache = true;

	/**
	 * 是否开启缓存
	 * @param enableCache
	 */
	public static void setEnableCache(boolean enableCache) {
		MpUtils.enableCache = enableCache;
	}

	private static boolean isSuccess(JSONObject response) {
		if(response == null) return false;

		Integer code = response.getInteger("errcode");
		if(code == null || Integer.valueOf(0).equals(code)) {
			return true;
		}

		return false;
	}

	/**
	 * 临时登录凭证 code 获取 Session
	 * <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html">详情</a>
	 * @param appId
	 * @param secret
	 * @param jsCode
	 * @return
	 */
	public static CodeSession getSessionByCode(String appId, String secret, String jsCode) {
		String url = UtilString.place("https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code", appId, secret, jsCode);

		try {
			String content = UtilHttp.getToText(url);

			logger.debug("[getCodeSession] response content: {}", content);


			JSONObject jsonObject = JSONObject.parseObject(content);

			if(isSuccess(jsonObject)) {
				CodeSession session = new CodeSession();
				session.setOpenid(jsonObject.getString("openid"));
				session.setSessionKey(jsonObject.getString("session_key"));
				session.setUnionid(jsonObject.getString("unionid"));
				return session;
			}
		} catch (Exception e) {
			logger.error("[getCodeSession] error", e);
		}

		return null;
	}
	
	/**
	 * key is AppId
	 */
	private final static UtilCache<AccessToken> accessTokenCache = UtilCache.createUtilCache("_mp_accessTokenCache_");
	
	/**
	 * 获取AccessToken
	 * <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html">详情</a>
	 * @param appid
	 * @param appsecret
	 * @return
	 */
	public static AccessToken getAccessToken(String appid, String appsecret) {
		AccessToken accessToken = null;

		if(enableCache){
			accessToken = accessTokenCache.get(appid);
		}

		if(accessToken == null) {
			accessToken = new AccessToken(appid);
			if(enableCache){
				accessTokenCache.put(appid, accessToken);
			}
		}

		if(!accessToken.isExpired()) {
			return accessToken;
		}

		String url = UtilString.place("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", appid, appsecret);

		try {
			String content = UtilHttp.getToText(url);

			logger.info("[getAccessToken] response content: {}", content);


			JSONObject jsonObject = JSONObject.parseObject(content);

			if(isSuccess(jsonObject)) {
				accessToken.refresh(jsonObject.getString("access_token"), jsonObject.getLongValue("expires_in") * 1000);
			}
		} catch (Exception e) {
			logger.error("[getAccessToken] error", e);
		}

		return accessToken;
	}
	
	/**
	 * 	解密用户信息
	 * 	<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html">描述文档</a>
	 * @param sessionKey
	 * @param encryptedData
	 * @param iv
	 * @return
	 */
	public static MpUserInfo decryptUserInfo(String sessionKey, String encryptedData, String iv) {
		try {
			byte[] resultByte = UtilAES.decrypt(Base64.getDecoder().decode(encryptedData), Base64.getDecoder().decode(sessionKey),
					Base64.getDecoder().decode(iv), "CBC", "PKCS7Padding");
			
			JSONObject jsonObject = JSONObject.parseObject(new String(resultByte, "UTF-8"));
			MpUserInfo userInfo = new MpUserInfo();
			userInfo.setCity(jsonObject.getString("city"));
			userInfo.setCountry(jsonObject.getString("country"));
			userInfo.setProvince(jsonObject.getString("province"));
			userInfo.setGender(jsonObject.getIntValue("gender") ==1?"Y":"M");
			userInfo.setHeadimgurl(jsonObject.getString("avatarUrl"));
			userInfo.setUnionid(jsonObject.getString("unionId"));
			userInfo.setNickname(jsonObject.getString("nickName"));
			userInfo.setOpenid(jsonObject.getString("openId"));

			return userInfo;
		} catch (Exception e) {
			logger.error("[decryptUserInfo] error", e);
		}

		return null;
	}

	/**
	 * 发送小程序模板消息
	 * <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/template-message/templateMessage.send.html">描述</a>
	 * @param accessToken
	 * @param message
	 * @return
	 */
	public static boolean sendTemplateMessage(String accessToken, MpTemplateMessage message){

		String url = UtilString.place("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={}", accessToken);

		try {
			RawData payload = new RawData();
			payload.setCharset("UTF-8");

			JSONObject jsonObject = new JSONObject();
			jsonObject.put("touser", message.getTouser());
			jsonObject.put("template_id", message.getTemplateId());
			jsonObject.put("form_id", message.getFormId());
			if(message.getData().isEmpty()){
				jsonObject.put("data", message.getData());
			}

			if(UtilString.isNotBlank(message.getEmphasisKeyword())){
				jsonObject.put("emphasis_keyword", message.getEmphasisKeyword());
			}

			if(UtilString.isNotBlank(message.getPage())){
				jsonObject.put("page", message.getPage());
			}

			payload.append(JSONObject.toJSONString(jsonObject));

			String content = UtilHttp.postToText(url, null, null, payload);

			logger.info("[sendTemplateMessage] response content: {}", content);


			jsonObject = JSONObject.parseObject(content);

			if(isSuccess(jsonObject)) {
				return true;
			}
		} catch (Exception e) {
			logger.error("[sendTemplateMessage] error", e);
		}

		return false;
	}
}
